package cn.bxshey.general.aop;

import cn.bxshey.general.Result.Result;
import cn.bxshey.general.aop.note.SystemLog;
import cn.bxshey.general.enums.ResultEnum;
import cn.bxshey.general.exception.BusinessException;
import cn.bxshey.general.util.HttpUtils;
import cn.bxshey.mq.constant.MQ;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @作者：不想说话而已
 * @Date：2023/12/6 12:49
 */
@Aspect //这是一个切面类
@Component
@Order(2)
public class SystemLogAop {

    @Resource
    HttpUtils httpUtils; //自定http工具类

    @Resource
    RabbitTemplate rabbitTemplate;

    @Around("@annotation(systemLog)")
    public Object systemLog(ProceedingJoinPoint joinPoint, SystemLog systemLog) throws Throwable {
        Calendar calendar_create = Calendar.getInstance();//请求开始时间
        Map<String, String> httpInfo = httpUtils.getHttpInfo(); //获取ip、地址等信息
        HttpServletRequest httpRequest = httpUtils.getHttpRequest(); //获取一个request对象
        Map<String, String> map = new HashMap<>(); //准备发送日志消息Map集合
        Object proceed;
        try {
            proceed = joinPoint.proceed(); //执行方法
            map.put("code", String.valueOf(ResultEnum.SUCCESS.code)); //请求响应码
        } catch (Exception e) {
            //如果是业务异常
           if(e instanceof BusinessException){
               BusinessException be = (BusinessException) e;
               proceed = Result.error(be.getCode(),be.getMessage());
               map.put("code", String.valueOf(be.getCode())); //请求响应码
           }else {
               proceed = Result.error(ResultEnum.ERROR.code,e.getMessage());
               map.put("code", String.valueOf(ResultEnum.ERROR.code)); //请求响应码
               map.put("error", getExceptionStackInfo(e)); //未知异常的详细信息
           }
        }
        Result<?> result = (Result<?>) proceed;

        map.put("msg", systemLog.value()); //日志描述
        map.put("args", Arrays.toString(joinPoint.getArgs())); //请求参数
        map.put("ip", httpInfo.get("ip"));//ip
        map.put("ip_city", httpInfo.get("city"));//请求地址归属地
        map.put("serve", systemLog.serve());//服务类别

        //返回值的相关处理
        Optional.ofNullable(result).flatMap(r -> Optional.ofNullable(result.getData())).ifPresent(d -> {
            Object data = result.getData();
            String resultData;
            if (data instanceof ArrayList) {
                //对返回内容去除空格/换行/制表符
                resultData = ((ArrayList<?>) data).toString().replaceAll("\\s*|\r|\n|\t", "");
            } else {
                resultData = String.valueOf(data);
            }
            map.put("result_data", String.valueOf(resultData));
        });

        map.put("request_method", joinPoint.getSignature().getName());//请求 所执行的方法
        map.put("request_url", String.valueOf(httpRequest.getRequestURL()));//请求 完整路径
        map.put("package_name", joinPoint.getTarget().getClass().getName());//请求所在包名

        Calendar calendar_end = Calendar.getInstance(); // 请求结束时间
        map.put("take", String.valueOf((calendar_end.getTimeInMillis() - calendar_create.getTimeInMillis()))); //耗时、单位/毫秒
        SimpleDateFormat sdf = new SimpleDateFormat(" yyyy-MM-dd HH:mm:ss ");
        String str = sdf.format(new Date());
        map.put("create_time", str); //请求开始时间

        rabbitTemplate.convertAndSend(MQ.EXCHANGE_LOG, MQ.KEY_LOG_INFO, map); //发送日志消息

        return proceed; //返回方法返回值
    }


    //返回 异常信息字符串
    private String getExceptionStackInfo(Exception e) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter printWriter = new PrintWriter(stringWriter);
        e.printStackTrace(printWriter);
        return stringWriter.toString();
    }


}
